1. 死锁

  • 进程和线程都会有死锁的现象

  • 两个或两个以上的进程/线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程/线程称为死锁进程/线程

  • 死锁的出行的情况: 在多线程并发的情况下,同一个线程中如果出现多次 acquire 就可能产生死锁线程现象

# 死锁的现象

from threading import Lock

lock = Lock()
lock.acquire()  # 上锁
lock.acquire()  # 在这里会一直等待解锁,因为上面已经上了一把锁了且它并没有解开,就会在这里一直等待下面的程序也没办法执行
print(123)
lock.release()
lock.release()


2. 死锁例子

  • 吃面例子: 每个线程只有拿到筷子和面的时候才能吃上面

import time
from threading import Thread
from threading import Lock

kz = Lock()  # 筷子锁
m = Lock()  # 面锁


def eat1(name):
    kz.acquire()
    print('%s,拿到筷子了' % name)
    m.acquire()
    print('%s,拿到面' % name)
    print('%s,吃面' % name)
    m.release()
    kz.release()


def eat2(name):
    m.acquire()
    print('%s,拿到面' % name)
    time.sleep(1)
    kz.acquire()
    print('%s,拿到筷子了' % name)
    print('%s,吃面' % name)
    kz.release()
    m.release()


Thread(target=eat1, args=('Kevin',)).start()
Thread(target=eat2, args=('Yeung',)).start()
Thread(target=eat1, args=('Jack',)).start()
Thread(target=eat2, args=('Amier',)).start()

# 执行结果
    # Kevin,拿到筷子了
    # Kevin,拿到面
    # Kevin,吃面
    # Yeung,拿到面
    # Jack,拿到筷子了 -> 一直会在这里等待着,因为当Kevin吃完面后,Yeung拿到了面的钥匙,Jack拿到了筷子锁的钥匙,两个线程分别拿着不同的钥匙,而程序需要一个线程同时拿到两把钥匙才能执行下去

3. 递归锁 -> 递归锁是解决死锁的办法

  • 进程中也有递归锁
  • 第一次进入程序的时候无论程序上面执行了多少次acquire(),它都会往执行。
  • 上面执行了 num 次 acquire() 上锁,程序下面就要执行 num 次 release() 解锁
  • 使用递归锁解决多线程中死锁问题必须使用同一把递归锁

from threading import RLock

r_lock = RLock()
r_lock.acquire()
r_lock.acquire() 
print(123)
r_lock.release()
r_lock.release()

4. 使用递归锁解决上面吃面例子的死锁问题

import time
from threading import Thread
from threading import RLock

m = kz = RLock()  # 使用递归锁解决多线程中死锁问题必须是同一把锁,如果也是多把递归锁也是会出现死锁问题


def eat1(name):
    kz.acquire()
    print('%s,拿到筷子了' % name)
    m.acquire()
    print('%s,拿到面' % name)
    print('%s,吃面' % name)
    m.release()
    kz.release()


def eat2(name):
    m.acquire()
    print('%s,拿到面' % name)
    time.sleep(1)
    kz.acquire()
    print('%s,拿到筷子了' % name)
    print('%s,吃面' % name)
    kz.release()
    m.release()


Thread(target=eat1, args=('Kevin',)).start()
Thread(target=eat2, args=('Yeung',)).start()
Thread(target=eat1, args=('Jack',)).start()
Thread(target=eat2, args=('Amier',)).start()